{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "abfe7cef-2bb1-4ec0-bfcb-91340ac2946c",
   "metadata": {},
   "source": [
    "- 本Notebook主要用于:\n",
    "    + Bge 向量模型的选型、调优，效果对比分析\n",
    "    + Bge Rerank模型的微调、效果对比分析\n",
    "\n",
    "**结合blog[<基于大语言模型知识问答应用落地实践 - 知识召回调优(下)>](https://aws.amazon.com/cn/blogs/china/practice-of-knowledge-question-answering-application-based-on-llm-knowledge-base-construction-part-4/)使用**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73337842-6f48-4df6-a3e1-d071a1864ce3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!pip install git+https://github.com/FlagOpen/FlagEmbedding.git -Uq\n",
    "!pip install -Uq sentence-transformers \n",
    "!pip install faiss-cpu -Uq"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95cd5298-0542-4e1a-8d45-1b9b561edf05",
   "metadata": {},
   "source": [
    "### Generate random negative label\n",
    "\n",
    "基于LLM增强的数据输入，生成BGE向量模型训练的数据，采用随机负采样的方式\n",
    "\n",
    "**LLM增强的输入数据(chatgpt_synthesis.jsonl)格式如下** \n",
    "```\n",
    "{\n",
    "    \"origin_question\": \"什么是 EMR Studio？\", \n",
    "    \"origin_answer\": \"EMR Studio 是一个集成开发环境 (IDE)，使数据科学家和数据工程师能够轻松地开发、可视化和调试用 R、Python、Scala 和 PySpark 编写的数据工程和数据科学应用程序。\\n它是一个完全托管的应用程序，具有单点登录、完全托管的 Jupyter Notebooks、自动基础设施预置，并且能够在不登录 AWS 控制台或集群的情况下调试作业。数据科学家和分析人员可以安装自定义内核和库，使用代码库（如 GitHub 和 BitBucket）与同事协作，或者使用 Apache Airflow、AWS Step Functions 和 Amazon Managed Workflows for Apache Airflow 等编排服务，将参数化笔记本作为计划工作流的一部分运行。 您可以使用 Amazon MWAA 读取 Amazon EMR 笔记本上的编排分析作业，以了解更多信息。EMR Studio 内核和应用程序在 EMR 集群上运行，因此您可以利用性能优化的适用于 Apache Spark 的 Amazon EMR 运行时，获得分布式数据处理带来的优势。管理员可以设置 EMR Studio，以便分析师可以在现有 EMR 集群上运行其应用程序，或使用 EMR 的预定义 AWS CloudFormation 模板创建新集群。\", \n",
    "    \"generate_question\": \"EMR Studio 是用来做什么的？\", \n",
    "    \"generate_answer\": \"EMR Studio 是一个集成开发环境 (IDE)，用于开发、可视化和调试数据工程和数据科学应用程序。\"\n",
    "}\n",
    "{\n",
    "    \"origin_question\": \"什么是 EMR Studio？\", \n",
    "    \"origin_answer\": \"EMR Studio 是一个集成开发环境 (IDE)，使数据科学家和数据工程师能够轻松地开发、可视化和调试用 R、Python、Scala 和 PySpark 编写的数据工程和数据科学应用程序。\\n它是一个完全托管的应用程序，具有单点登录、完全托管的 Jupyter Notebooks、自动基础设施预置，并且能够在不登录 AWS 控制台或集群的情况下调试作业。数据科学家和分析人员可以安装自定义内核和库，使用代码库（如 GitHub 和 BitBucket）与同事协作，或者使用 Apache Airflow、AWS Step Functions 和 Amazon Managed Workflows for Apache Airflow 等编排服务，将参数化笔记本作为计划工作流的一部分运行。 您可以使用 Amazon MWAA 读取 Amazon EMR 笔记本上的编排分析作业，以了解更多信息。EMR Studio 内核和应用程序在 EMR 集群上运行，因此您可以利用性能优化的适用于 Apache Spark 的 Amazon EMR 运行时，获得分布式数据处理带来的优势。管理员可以设置 EMR Studio，以便分析师可以在现有 EMR 集群上运行其应用程序，或使用 EMR 的预定义 AWS CloudFormation 模板创建新集群。\", \n",
    "    \"generate_question\": \"EMR Studio 支持哪些编程语言？\",\n",
    "    \"generate_answer\": \"EMR Studio 支持 R、Python、Scala 和 PySpark 这些编程语言。\"\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "id": "7a3dd10b-b601-4165-b902-f2e4ac5baa95",
   "metadata": {},
   "outputs": [],
   "source": [
    "# use LLM enhanced data\n",
    "import random\n",
    "import json\n",
    "import os\n",
    "FAQ_FILE = 'chatgpt_synthesis.jsonl'\n",
    "\n",
    "def generate_train_data(train_data, output_suffix='train'):\n",
    "    size_train_data = len(train_data)\n",
    "    qq_labels = []\n",
    "    gqga_labels = []\n",
    "    gqoa_labels = []\n",
    "    for line in train_data:\n",
    "        json_obj = json.loads(line)\n",
    "        \n",
    "        o_query = json_obj['origin_question'].strip()\n",
    "        o_answer = json_obj['origin_answer']\n",
    "        g_query = json_obj['generate_question']\n",
    "        g_answer = json_obj['generate_answer']\n",
    "        \n",
    "        # 可能的召回策略是：\n",
    "        # 知识库构建时，o_query，g_query，o_answer，g_answer 均做向量化。\n",
    "        # 查询时去做QQ召回，QA召回\n",
    "        \n",
    "        # 求 origin_Q - generated_Q 的相似性， 判断QQ召回的可行性\n",
    "        qq_labels.append((o_query, g_query)) \n",
    "        \n",
    "        #求 origin_Q - generated_D 的相似性， 判断QD召回的可行性\n",
    "        gqga_labels.append((g_query, g_answer)) \n",
    "        \n",
    "        #求 origin_Q - origin_D 的相似性， 判断QD召回的可行性\n",
    "        gqoa_labels.append((g_query, o_answer))\n",
    "        \n",
    "    qq1_file = open(f\"chatgpt_synthesis/qq1_{output_suffix}.jsonl\", 'w')\n",
    "    for idx, (query_a, query_b) in enumerate(qq_labels):\n",
    "        N = range(len(qq_labels))\n",
    "        m = 20\n",
    "        idx_list = random.sample(N, m)\n",
    "        neg_list = [ qq_labels[i][1] for i in idx_list if i != idx ]\n",
    "        record = json.dumps({ \"query\": query_a, \"pos\": [query_b], \"neg\": neg_list }, ensure_ascii=False)\n",
    "        qq1_file.write(record)\n",
    "        qq1_file.write('\\n')\n",
    "        \n",
    "    qq2_file = open(f\"chatgpt_synthesis/qq2_{output_suffix}.jsonl\", 'w')\n",
    "    for idx, (query_a, query_b) in enumerate(qq_labels):\n",
    "        N = range(len(qq_labels))\n",
    "        m = 20\n",
    "        idx_list = random.sample(N, m)\n",
    "        neg_list = [ qq_labels[i][0] for i in idx_list if i != idx ]\n",
    "        record = json.dumps({ \"query\": query_a, \"pos\": [query_b], \"neg\": neg_list }, ensure_ascii=False)\n",
    "        qq2_file.write(record)\n",
    "        qq2_file.write('\\n')\n",
    "    \n",
    "    oqgd_file = open(f\"chatgpt_synthesis/gqga_{output_suffix}.jsonl\", 'w')\n",
    "    for idx, (query_g, answer_g) in enumerate(gqga_labels):\n",
    "        N = range(len(gqga_labels))\n",
    "        m = 20\n",
    "        idx_list = random.sample(N, m)\n",
    "        neg_list = [ gqga_labels[i][1] for i in idx_list if i != idx ]\n",
    "        record = json.dumps({ \"query\": \"为这个句子生成表示以用于检索相关文章：\" + query_g, \"pos\": [answer_g], \"neg\": neg_list }, ensure_ascii=False)\n",
    "        oqgd_file.write(record)\n",
    "        oqgd_file.write('\\n')\n",
    "        \n",
    "    gqod_file = open(f\"chatgpt_synthesis/gqoa_{output_suffix}.jsonl\", 'w')\n",
    "    for idx, (query_g, answer_o) in enumerate(gqoa_labels):\n",
    "        N = range(len(gqoa_labels))\n",
    "        m = 20\n",
    "        idx_list = random.sample(N, m)\n",
    "        neg_list = [ gqoa_labels[i][1] for i in idx_list if i != idx ]\n",
    "        record = json.dumps({ \"query\": \"为这个句子生成表示以用于检索相关文章：\" + query_g, \"pos\": [answer_o], \"neg\": neg_list }, ensure_ascii=False)\n",
    "        gqod_file.write(record)\n",
    "        gqod_file.write('\\n')\n",
    "    \n",
    "\n",
    "test_data= None\n",
    "train_data = None\n",
    "with open(FAQ_FILE, 'r') as file:\n",
    "    data_arr = file.readlines()\n",
    "    data_count = len(data_arr)\n",
    "    train_count = int(data_count * 0.9)\n",
    "    test_count = data_count - train_count\n",
    "    test_data = data_arr[:test_count]\n",
    "    train_data = data_arr[test_count:]\n",
    "    valid_data = data_arr[train_count:]\n",
    "    \n",
    "if not os.path.exists('chatgpt_synthesis'):\n",
    "    os.mkdir('chatgpt_synthesis')\n",
    "generate_train_data(test_data, 'test')\n",
    "generate_train_data(train_data, 'train')\n",
    "generate_train_data(valid_data, 'valid')\n",
    "\n",
    "def generate_FAQ(data_arr, sep='\\n=====\\n', faq_name='enhanced_faq'):\n",
    "    def generate_item(data_arr):\n",
    "        for line in data_arr:\n",
    "            json_obj = json.loads(line)\n",
    "\n",
    "            o_query = json_obj['origin_question'].strip()\n",
    "            o_answer = json_obj['origin_answer']\n",
    "            g_query = json_obj['generate_question']\n",
    "            g_answer = json_obj['generate_answer']\n",
    "\n",
    "            faq_template = \"Question: {}\\nAnswer: {}\"\n",
    "\n",
    "            if len(o_query) > 5:\n",
    "                faq1 = faq_template.format(o_query, o_answer)\n",
    "                yield faq1\n",
    "            faq2 = faq_template.format(g_query, o_answer)\n",
    "            yield faq2\n",
    "            faq3 = faq_template.format(g_query, g_answer)\n",
    "            yield faq3\n",
    "            \n",
    "    with open(f\"{faq_name}.faq\", 'w') as outfile:\n",
    "        no_dup_kg = list(set(generate_item(data_arr)))\n",
    "        outfile.write(sep.join(no_dup_kg))\n",
    "\n",
    "generate_FAQ(data_arr, faq_name=\"chatgpt_enhanced_faq\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96489db5-0989-4d56-bc6f-a37d1a1e09f8",
   "metadata": {},
   "source": [
    "### Generate train/test data\n",
    "\n",
    "合并上面生成的各个数据得到训练集和测试集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "5d4d5113-c73d-4ab7-9e95-66f0cc12900d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!cat ./chatgpt_synthesis/*train.jsonl > chatgpt_synthesis/train_merged.jsonl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "id": "de8e7d4c-53ce-4968-94cd-5dee52b6e190",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "26268 chatgpt_synthesis/train_merged.jsonl\n"
     ]
    }
   ],
   "source": [
    "!wc -l chatgpt_synthesis/train_merged.jsonl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "id": "f71fd37e-7f55-4234-a308-f5bdb140c13e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!cat ./chatgpt_synthesis/*test.jsonl > chatgpt_synthesis/test_merged.jsonl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "id": "de63e1ae-a552-4b3c-a58e-1d789f095360",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2920 chatgpt_synthesis/test_merged.jsonl\n"
     ]
    }
   ],
   "source": [
    "!wc -l chatgpt_synthesis/test_merged.jsonl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "f7eda27e-2b71-4bb8-92f6-f970ab0c6025",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!cat ./chatgpt_synthesis/*valid.jsonl > chatgpt_synthesis/valid_merged.jsonl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "id": "913671f7-88f1-4226-b613-ba57a24d2351",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2920 chatgpt_synthesis/valid_merged.jsonl\n"
     ]
    }
   ],
   "source": [
    "!wc -l chatgpt_synthesis/valid_merged.jsonl"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5fd44c3-f02c-4cd9-b948-49fb752c98c4",
   "metadata": {},
   "source": [
    "### Finetune Bge-large-zh-v1.5\n",
    "每一百步打印loss，注意观察loss的变化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a5d6c851-9daa-4b5f-b309-5a1857427e42",
   "metadata": {},
   "outputs": [],
   "source": [
    "!torchrun --nproc_per_node 4 \\\n",
    "-m FlagEmbedding.baai_general_embedding.finetune.run \\\n",
    "--output_dir ./finetune_bge_large_zh15 \\\n",
    "--model_name_or_path BAAI/bge-large-zh-v1.5 \\\n",
    "--train_data ./chatgpt_synthesis/train_merged.jsonl \\\n",
    "--learning_rate 1e-5 \\\n",
    "--fp16 \\\n",
    "--num_train_epochs 5 \\\n",
    "--per_device_train_batch_size 1 \\\n",
    "--normlized True \\\n",
    "--temperature 0.02 \\\n",
    "--query_max_len 128 \\\n",
    "--passage_max_len 512 \\\n",
    "--train_group_size 9 \\\n",
    "--logging_steps 100 "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac5eda6f-eddb-4512-ad5a-0381ce97e3bc",
   "metadata": {},
   "source": [
    "### Generate hard negative label (optional)\n",
    "\n",
    "这步主要是为了得到Ranker模型的训练数据和测试数据，分别进行抽取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "77927f04-c4fc-42a2-b776-3cb28299e30d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!python -m FlagEmbedding.baai_general_embedding.finetune.hn_mine \\\n",
    "--model_name_or_path BAAI/bge-large-zh \\\n",
    "--input_file chatgpt_synthesis/train_merged.jsonl \\\n",
    "--output_file chatgpt_synthesis/train_merged_minedHN.jsonl \\\n",
    "--range_for_sampling 2-200"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "id": "b5ee71c7-0d93-4984-b315-2e92012eccfd",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "out_file = open('chatgpt_synthesis/train_merged_hardneg.jsonl', 'w')\n",
    "with open('chatgpt_synthesis/train_merged_minedHN.jsonl', 'r') as file:\n",
    "    for line in file.readlines():\n",
    "        json_obj = json.loads(line)\n",
    "        out_file.write(json.dumps(json_obj, ensure_ascii=False))\n",
    "        out_file.write('\\n')\n",
    "        \n",
    "out_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6681472d-95d6-4665-bb45-81d0b84f79ac",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!python -m FlagEmbedding.baai_general_embedding.finetune.hn_mine \\\n",
    "--model_name_or_path BAAI/bge-large-zh \\\n",
    "--input_file chatgpt_synthesis/test_merged.jsonl \\\n",
    "--output_file chatgpt_synthesis/test_merged_minedHN.jsonl \\\n",
    "--range_for_sampling 2-200"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 149,
   "id": "34e59825-ff34-4e5a-bb90-c4cc5fecb3e7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "out_file = open('chatgpt_synthesis/test_merged_hardneg.jsonl', 'w')\n",
    "with open('chatgpt_synthesis/test_merged_minedHN.jsonl', 'r') as file:\n",
    "    for line in file.readlines():\n",
    "        json_obj = json.loads(line)\n",
    "        out_file.write(json.dumps(json_obj, ensure_ascii=False))\n",
    "        out_file.write('\\n')\n",
    "        \n",
    "out_file.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10308384-4ee7-49b0-a9e5-260da343d370",
   "metadata": {},
   "source": [
    "### Train For Reranker\n",
    "\n",
    "训练Rerank模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61a36406-918f-4de3-add2-3375ed9e2faa",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!torchrun --nproc_per_node 4 \\\n",
    "-m FlagEmbedding.reranker.run \\\n",
    "--output_dir ./rerank_bge_base_zh15 \\\n",
    "--model_name_or_path BAAI/bge-reranker-base \\\n",
    "--train_data ./chatgpt_synthesis/train_merged_hardneg.jsonl \\\n",
    "--learning_rate 6e-5 \\\n",
    "--fp16 \\\n",
    "--num_train_epochs 3 \\\n",
    "--per_device_train_batch_size 1 \\\n",
    "--gradient_accumulation_steps 4 \\\n",
    "--dataloader_drop_last True \\\n",
    "--train_group_size 9 \\\n",
    "--max_len 512 \\\n",
    "--weight_decay 0.01 \\\n",
    "--logging_steps 100"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bbdaa050-ecc4-4ecf-819e-e663529e2dce",
   "metadata": {},
   "source": [
    "### Prepare Finetuned Embedding Model Configuration\n",
    "\n",
    "准备微调后的Embedding配置信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "id": "62c8f0e8-10d2-46f1-823d-fff5c079906d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sagemaker\n",
    "from sagemaker import image_uris\n",
    "import boto3\n",
    "import os\n",
    "import time\n",
    "import json\n",
    "\n",
    "role = sagemaker.get_execution_role()  # execution role for the endpoint\n",
    "sess = sagemaker.session.Session()  # sagemaker session for interacting with different AWS APIs\n",
    "bucket = sess.default_bucket()  # bucket to house artifacts\n",
    "\n",
    "region = sess._region_name\n",
    "account_id = sess.account_id()\n",
    "\n",
    "s3_client = boto3.client(\"s3\")\n",
    "sm_client = boto3.client(\"sagemaker\")\n",
    "smr_client = boto3.client(\"sagemaker-runtime\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "e1023771-e979-4af8-9c7e-cb386bca0157",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "s3_code_prefix: LLM-RAG/workshop/finetuned-bge15-large-zh-code\n",
      "model_snapshot_path: ./finetune_bge_large_zh15\n"
     ]
    }
   ],
   "source": [
    "s3_model_prefix = \"LLM-RAG/workshop/finetuned-bge15-large-zh-model\"  # folder where model checkpoint will go\n",
    "model_snapshot_path = \"./finetune_bge_large_zh15\"\n",
    "s3_code_prefix = \"LLM-RAG/workshop/finetuned-bge15-large-zh-code\"\n",
    "print(f\"s3_code_prefix: {s3_code_prefix}\")\n",
    "print(f\"model_snapshot_path: {model_snapshot_path}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "733c9406-be14-4a80-b625-6c339aaf611f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!aws s3 cp --recursive {model_snapshot_path} s3://{bucket}/{s3_model_prefix}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "dc6094f6-f99d-414b-b7b3-14701b05d926",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Image going to be used is ---- > 763104351884.dkr.ecr.us-east-1.amazonaws.com/djl-inference:0.23.0-deepspeed0.9.5-cu118\n"
     ]
    }
   ],
   "source": [
    "inference_image_uri = (\n",
    "    f\"763104351884.dkr.ecr.{region}.amazonaws.com/djl-inference:0.23.0-deepspeed0.9.5-cu118\"\n",
    ")\n",
    "\n",
    "#中国区需要替换为下面的image_uri\n",
    "# inference_image_uri = (\n",
    "#     f\"727897471807.dkr.ecr.{region}.amazonaws.com.cn/djl-inference:0.21.0-deepspeed0.8.3-cu117\"\n",
    "# )\n",
    "\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "98d9ef4d-26a0-47c3-95f9-81887b7ef675",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!mkdir -p finetuned-bge15-large-zh-code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "02719fb0-cc87-4d5e-9c11-c3552ffafdd7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting finetuned-bge15-large-zh-code/model.py\n"
     ]
    }
   ],
   "source": [
    "%%writefile finetuned-bge15-large-zh-code/model.py\n",
    "from djl_python import Input, Output\n",
    "import torch\n",
    "import logging\n",
    "import math\n",
    "import os\n",
    "from FlagEmbedding import FlagModel\n",
    "\n",
    "device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n",
    "print(f'--device={device}')\n",
    "\n",
    "def load_model(properties):\n",
    "    tensor_parallel = properties[\"tensor_parallel_degree\"]\n",
    "    model_location = properties['model_dir']\n",
    "    if \"model_id\" in properties:\n",
    "        model_location = properties['model_id']\n",
    "    logging.info(f\"Loading model in {model_location}\")\n",
    "\n",
    "    model =  FlagModel(model_location)\n",
    "    \n",
    "    return model\n",
    "\n",
    "model = None\n",
    "\n",
    "def handle(inputs: Input):\n",
    "    global model\n",
    "    if not model:\n",
    "        model = load_model(inputs.get_properties())\n",
    "\n",
    "    if inputs.is_empty():\n",
    "        return None\n",
    "    data = inputs.get_as_json()\n",
    "    \n",
    "    input_sentences = None\n",
    "    inputs = data[\"inputs\"]\n",
    "    if isinstance(inputs, list):\n",
    "        input_sentences = inputs\n",
    "    else:\n",
    "        input_sentences =  [inputs]\n",
    "        \n",
    "    is_query = data[\"is_query\"]\n",
    "    instruction = data[\"instruction\"]\n",
    "    logging.info(f\"inputs: {input_sentences}\")\n",
    "    logging.info(f\"is_query: {is_query}\")\n",
    "    logging.info(f\"instruction: {instruction}\")\n",
    "    \n",
    "    if is_query and instruction:\n",
    "        input_sentences = [ instruction + sent for sent in input_sentences ]\n",
    "        \n",
    "    sentence_embeddings =  model.encode(input_sentences)\n",
    "        \n",
    "    result = {\"sentence_embeddings\": sentence_embeddings}\n",
    "    return Output().add_as_json(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "b5e13400-5f2a-4097-bd6d-9719d0a0702f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "option.s3url ==> s3://sagemaker-us-east-1-106839800180/LLM-RAG/workshop/finetuned-bge15-large-zh-model/\n"
     ]
    }
   ],
   "source": [
    "print(f\"option.s3url ==> s3://{bucket}/{s3_model_prefix}/\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74e1306d-3c59-404c-8a46-52d53aa1f7ac",
   "metadata": {},
   "source": [
    "#### 设置 serving.properties，requirements.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "id": "3b23a17d-9de1-4a32-a7d3-139eb64098df",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "with open('finetuned-bge15-large-zh-code/serving.properties', 'w') as file:\n",
    "    prop = f\"\"\"engine=Python\n",
    "option.tensor_parallel_degree=1\n",
    "option.s3url = s3://{bucket}/{s3_model_prefix}/\"\"\"\n",
    "    file.write(prop)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "79c92fc5-f4f4-419c-af32-3b11db3cbef2",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "with open('finetuned-bge15-large-zh-code/requirements.txt', 'w') as file:\n",
    "    requirements = \"\"\"transformers==4.28.1\\nFlagEmbedding\"\"\"\n",
    "    file.write(requirements)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "98ab64e7-4d3e-4219-a8dc-2ff30a89bb86",
   "metadata": {},
   "outputs": [],
   "source": [
    "!rm s2e_model.tar.gz\n",
    "!cd finetuned-bge15-large-zh-code && rm -rf \".ipynb_checkpoints\"\n",
    "!tar czvf s2e_model.tar.gz finetuned-bge15-large-zh-code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "5ad5e4f1-350e-4fdc-9647-cc58da41a6f0",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "S3 Code or Model tar ball uploaded to --- > s3://sagemaker-us-east-1-106839800180/LLM-RAG/workshop/finetuned-bge15-large-zh-code/s2e_model.tar.gz\n"
     ]
    }
   ],
   "source": [
    "s3_code_artifact = sess.upload_data(\"s2e_model.tar.gz\", bucket, s3_code_prefix)\n",
    "print(f\"S3 Code or Model tar ball uploaded to --- > {s3_code_artifact}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "716241c8-b883-44ea-930e-1931a4d359f3",
   "metadata": {},
   "source": [
    "### Setup Finetuned Embedding model Endpoint \n",
    "\n",
    "创建微调模型 & 创建endpoint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "517a6ae9-d0af-4835-871a-1389573b23a6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sagemaker.utils import name_from_base\n",
    "import boto3\n",
    "\n",
    "model_name = name_from_base(\"bge15-finetuned\") #Note: Need to specify model_name\n",
    "print(model_name)\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")\n",
    "\n",
    "create_model_response = sm_client.create_model(\n",
    "    ModelName=model_name,\n",
    "    ExecutionRoleArn=role,\n",
    "    PrimaryContainer={\n",
    "        \"Image\": inference_image_uri,\n",
    "        \"ModelDataUrl\": s3_code_artifact\n",
    "    },\n",
    "    \n",
    ")\n",
    "model_arn = create_model_response[\"ModelArn\"]\n",
    "\n",
    "print(f\"Created Model: {model_arn}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40203a41-93b7-4c35-a108-50febae4bb4c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "endpoint_config_name = f\"{model_name}-config\"\n",
    "endpoint_name = f\"{model_name}-endpoint\"\n",
    "\n",
    "endpoint_config_response = sm_client.create_endpoint_config(\n",
    "    EndpointConfigName=endpoint_config_name,\n",
    "    ProductionVariants=[\n",
    "        {\n",
    "            \"VariantName\": \"variant1\",\n",
    "            \"ModelName\": model_name,\n",
    "            \"InstanceType\": \"ml.g4dn.xlarge\",\n",
    "            \"InitialInstanceCount\": 1,\n",
    "            # \"VolumeSizeInGB\" : 400,\n",
    "            # \"ModelDataDownloadTimeoutInSeconds\": 2400,\n",
    "            \"ContainerStartupHealthCheckTimeoutInSeconds\": 15*60,\n",
    "        },\n",
    "    ],\n",
    ")\n",
    "endpoint_config_response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4c669b1a-c2d9-4243-812b-d8f0cef6940f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "create_endpoint_response = sm_client.create_endpoint(\n",
    "    EndpointName=f\"{endpoint_name}\", EndpointConfigName=endpoint_config_name\n",
    ")\n",
    "print(f\"Created Endpoint: {create_endpoint_response['EndpointArn']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30380eda-37a9-4064-b66c-49b335700671",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "status = resp[\"EndpointStatus\"]\n",
    "print(\"Status: \" + status)\n",
    "\n",
    "while status == \"Creating\":\n",
    "    time.sleep(60)\n",
    "    resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "    status = resp[\"EndpointStatus\"]\n",
    "    print(\"Status: \" + status)\n",
    "\n",
    "print(\"Arn: \" + resp[\"EndpointArn\"])\n",
    "print(\"Status: \" + status)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00b098f9-c649-4ba2-9e7a-7c994026ae23",
   "metadata": {
    "tags": []
   },
   "source": [
    "### Test Embedding model Endpoint \n",
    "\n",
    "测试向量模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1cc423d4-04c1-4f84-8ea2-856631b81df0",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def get_vector_by_sm_endpoint(questions, sm_client, endpoint_name):\n",
    "    parameters = {\n",
    "    }\n",
    "\n",
    "    response_model = sm_client.invoke_endpoint(\n",
    "        EndpointName=endpoint_name,\n",
    "        Body=json.dumps(\n",
    "            {\n",
    "                \"inputs\": questions,\n",
    "                \"is_query\": True,\n",
    "                \"instruction\" :  \"Represent this sentence for searching relevant passages:\"\n",
    "            }\n",
    "        ),\n",
    "        ContentType=\"application/json\",\n",
    "    )\n",
    "    # 中文instruction => 为这个句子生成表示以用于检索相关文章：\n",
    "    json_str = response_model['Body'].read().decode('utf8')\n",
    "    json_obj = json.loads(json_str)\n",
    "    embeddings = json_obj['sentence_embeddings']\n",
    "    return embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "79431143-c5ed-4c8d-8751-c0710e85793b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "prompts1 = [\"what is the default brightness setting on this device?\", \"how are you going\"]\n",
    "\n",
    "emb = get_vector_by_sm_endpoint(prompts1, smr_client, endpoint_name)\n",
    "print(len(emb[0]))\n",
    "print(emb)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0fbbbbb-ff7d-49d8-8664-60d440a6618d",
   "metadata": {},
   "source": [
    "####  **【注意】部署完finetune后的模型后，如果需要对比微调前后的向量模型质量，可以转到同目录的另外一个notebook : visualize_emb_benchmark.ipynb**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79c33ed4-8f56-4a3c-bd63-24abeeaf5d9c",
   "metadata": {},
   "source": [
    "### Deploy Rerank model\n",
    "\n",
    "部署Rerank 模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "id": "a29a6fa8-c191-4588-951d-fc7be1e204c1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "s3_code_prefix: LLM-RAG/workshop/finetuned-bge-reranker-base-code\n",
      "model_snapshot_path: ./rerank_bge_base_zh15\n"
     ]
    }
   ],
   "source": [
    "s3_model_prefix = \"LLM-RAG/workshop/finetuned-bge-reranker-base-model\"  # folder where model checkpoint will go\n",
    "model_snapshot_path = \"./rerank_bge_base_zh15\"\n",
    "s3_code_prefix = \"LLM-RAG/workshop/finetuned-bge-reranker-base-code\"\n",
    "print(f\"s3_code_prefix: {s3_code_prefix}\")\n",
    "print(f\"model_snapshot_path: {model_snapshot_path}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f884b51-0894-4475-b77b-38950922c872",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!aws s3 cp --recursive {model_snapshot_path} s3://{bucket}/{s3_model_prefix}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f992eb7-9fe4-4986-9961-841d786bf803",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "inference_image_uri = (\n",
    "    f\"763104351884.dkr.ecr.{region}.amazonaws.com/djl-inference:0.23.0-deepspeed0.9.5-cu118\"\n",
    ")\n",
    "\n",
    "#中国区需要替换为下面的image_uri\n",
    "# inference_image_uri = (\n",
    "#     f\"727897471807.dkr.ecr.{region}.amazonaws.com.cn/djl-inference:0.21.0-deepspeed0.8.3-cu117\"\n",
    "# )\n",
    "\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "id": "a9b1ffaf-946a-4c3b-a267-7400d71be889",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "!mkdir -p finetuned-bge-reranker-base-code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "id": "93ca1da6-851a-4b01-a2e6-93d30d904939",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%writefile finetuned-bge-reranker-base-code/model.py\n",
    "from djl_python import Input, Output\n",
    "import torch\n",
    "import logging\n",
    "import math\n",
    "import os\n",
    "from FlagEmbedding import FlagReranker\n",
    "\n",
    "device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n",
    "print(f'--device={device}')\n",
    "\n",
    "def load_model(properties):\n",
    "    tensor_parallel = properties[\"tensor_parallel_degree\"]\n",
    "    model_location = properties['model_dir']\n",
    "    if \"model_id\" in properties:\n",
    "        model_location = properties['model_id']\n",
    "    logging.info(f\"Loading model in {model_location}\")\n",
    "\n",
    "    reranker = FlagReranker(model_location, use_fp16=True)\n",
    "    \n",
    "    return reranker\n",
    "\n",
    "reranker = None\n",
    "\n",
    "def handle(inputs: Input):\n",
    "    global reranker\n",
    "    if not reranker:\n",
    "        reranker = load_model(inputs.get_properties())\n",
    "\n",
    "    if inputs.is_empty():\n",
    "        return None\n",
    "    data = inputs.get_as_json()\n",
    "    \n",
    "    inputs = data[\"inputs\"]\n",
    "    inputs_batch = []\n",
    "    if len(inputs) == 0:\n",
    "        result = {\"error\": \"empty inputs\" }\n",
    "        return Output().add_as_json(result)\n",
    "    else:\n",
    "        if isinstance(inputs[0], str):\n",
    "            inputs_batch.append(inputs)\n",
    "        elif isinstance(inputs[0], list):\n",
    "            inputs_batch = inputs\n",
    "        else:\n",
    "            result = {\"error\": \"unsupport input type, please input with [['sent1', 'sent2'], ...]\" }\n",
    "            return Output().add_as_json(result)\n",
    "    \n",
    "    scores = reranker.compute_score(inputs_batch)\n",
    "    \n",
    "    result = {\"scores\": scores}\n",
    "    return Output().add_as_json(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94da0b18-8ac4-47bb-bc64-13904169d66d",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os \n",
    "\n",
    "with open('finetuned-bge-reranker-base-code/serving.properties', 'w') as file:\n",
    "    prop = f\"\"\"engine=Python\n",
    "option.tensor_parallel_degree=1\n",
    "option.s3url = s3://{bucket}/{s3_model_prefix}/\"\"\"\n",
    "    file.write(prop)\n",
    "    \n",
    "with open('finetuned-bge-reranker-base-code/requirements.txt', 'w') as file:\n",
    "    requirements = \"\"\"transformers==4.28.1\\nFlagEmbedding\"\"\"\n",
    "    file.write(requirements)\n",
    "    \n",
    "os.system('rm bge_rank_model.tar.gz')\n",
    "os.system('cd finetuned-bge-reranker-base-code && rm -rf \".ipynb_checkpoints\"')\n",
    "os.system('tar czvf bge_rank_model.tar.gz finetuned-bge-reranker-base-code')\n",
    "\n",
    "s3_code_artifact = sess.upload_data(\"bge_rank_model.tar.gz\", bucket, s3_code_prefix)\n",
    "print(f\"S3 Code or Model tar ball uploaded to --- > {s3_code_artifact}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e061b52-dc90-4cc5-a392-a460e2a98a7b",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sagemaker.utils import name_from_base\n",
    "import boto3\n",
    "\n",
    "model_name = name_from_base(\"bge-ranker\") #Note: Need to specify model_name\n",
    "print(model_name)\n",
    "print(f\"Image going to be used is ---- > {inference_image_uri}\")\n",
    "\n",
    "create_model_response = sm_client.create_model(\n",
    "    ModelName=model_name,\n",
    "    ExecutionRoleArn=role,\n",
    "    PrimaryContainer={\n",
    "        \"Image\": inference_image_uri,\n",
    "        \"ModelDataUrl\": s3_code_artifact\n",
    "    },\n",
    "    \n",
    ")\n",
    "model_arn = create_model_response[\"ModelArn\"]\n",
    "\n",
    "print(f\"Created Model: {model_arn}\")\n",
    "\n",
    "endpoint_config_name = f\"{model_name}-config\"\n",
    "endpoint_name = f\"{model_name}-endpoint\"\n",
    "\n",
    "endpoint_config_response = sm_client.create_endpoint_config(\n",
    "    EndpointConfigName=endpoint_config_name,\n",
    "    ProductionVariants=[\n",
    "        {\n",
    "            \"VariantName\": \"variant1\",\n",
    "            \"ModelName\": model_name,\n",
    "            \"InstanceType\": \"ml.g4dn.xlarge\",\n",
    "            \"InitialInstanceCount\": 1,\n",
    "            # \"VolumeSizeInGB\" : 400,\n",
    "            # \"ModelDataDownloadTimeoutInSeconds\": 2400,\n",
    "            \"ContainerStartupHealthCheckTimeoutInSeconds\": 15*60,\n",
    "        },\n",
    "    ],\n",
    ")\n",
    "\n",
    "print(f\"Created Endpoint Config: {endpoint_config_response}\")\n",
    "\n",
    "create_endpoint_response = sm_client.create_endpoint(\n",
    "    EndpointName=f\"{endpoint_name}\", EndpointConfigName=endpoint_config_name\n",
    ")\n",
    "print(f\"Created Endpoint: {create_endpoint_response['EndpointArn']}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "582de5c7-eab9-47c6-9239-4ff5c4e65296",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "status = resp[\"EndpointStatus\"]\n",
    "print(\"Status: \" + status)\n",
    "\n",
    "while status == \"Creating\":\n",
    "    time.sleep(60)\n",
    "    resp = sm_client.describe_endpoint(EndpointName=endpoint_name)\n",
    "    status = resp[\"EndpointStatus\"]\n",
    "    print(\"Status: \" + status)\n",
    "\n",
    "print(\"Arn: \" + resp[\"EndpointArn\"])\n",
    "print(\"Status: \" + status)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7950dfc-8da0-467f-a248-8d3780673871",
   "metadata": {},
   "source": [
    "### Verify Rerank performance\n",
    "\n",
    "验证Rerank 模型的效果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 207,
   "id": "febc218c-8c62-4663-8dd6-d9acd4547b31",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from collections import Counter\n",
    "import random\n",
    "\n",
    "def calc_emb_similarity(recall_pairs, sm_client, emb_endpoint_name=''):\n",
    "    def call_emb_model(sentences, sm_client, emb_endpoint_name):\n",
    "        response_model = sm_client.invoke_endpoint(\n",
    "            EndpointName=emb_endpoint_name,\n",
    "            Body=json.dumps(\n",
    "                {\n",
    "                    \"inputs\": sentences,\n",
    "                    \"is_query\": True,\n",
    "                    \"instruction\" : \"\",\n",
    "                    \"parameters\" : \"\"\n",
    "                }\n",
    "            ),\n",
    "            ContentType=\"application/json\",\n",
    "        )\n",
    "\n",
    "        json_str = response_model['Body'].read().decode('utf8')\n",
    "        json_obj = json.loads(json_str)\n",
    "        embeddings = json_obj['sentence_embeddings']\n",
    "        return embeddings[0]\n",
    "    \n",
    "    def similarity_calc(vec1, vec2):\n",
    "        dot_product = np.dot(vec1, vec2)\n",
    "        norm_vec1 = np.sqrt(np.dot(vec1, vec1))\n",
    "        norm_vec2 = np.sqrt(np.dot(vec2, vec2))\n",
    "        cosine_sim = dot_product / (norm_vec1 * norm_vec2)\n",
    "\n",
    "        return cosine_sim\n",
    "    \n",
    "    pair_a_embs= [ call_emb_model(item[0], sm_client, emb_endpoint_name) for item in recall_pairs ]\n",
    "    pair_b_embs= [ call_emb_model(item[1], sm_client, emb_endpoint_name) for item in recall_pairs ]\n",
    "    \n",
    "    score_list = []\n",
    "    for idx in range(len(pair_a_embs)):\n",
    "        score = similarity_calc(pair_a_embs[idx], pair_b_embs[idx])\n",
    "        score_list.append(score)\n",
    "    \n",
    "    return score_list\n",
    "\n",
    "def call_ranker(recall_pairs, sm_client, endpoint_name):\n",
    "    response_model = sm_client.invoke_endpoint(\n",
    "        EndpointName=endpoint_name,\n",
    "        Body=json.dumps(\n",
    "            {\n",
    "                \"inputs\": recall_pairs\n",
    "            }\n",
    "        ),\n",
    "        ContentType=\"application/json\",\n",
    "    )\n",
    "\n",
    "    json_str = response_model['Body'].read().decode('utf8')\n",
    "    json_obj = json.loads(json_str)\n",
    "    scores = json_obj['scores']\n",
    "    if isinstance(scores, list):\n",
    "        return zip(recall_pairs, scores)\n",
    "    else:\n",
    "        return zip(recall_pairs, [scores])\n",
    "    \n",
    "def plot_stat(pos_rank_list):\n",
    "    def gen_label_name(k):\n",
    "        return \"other\" if k > 4 else f\"Top{k+1}\" \n",
    "    \n",
    "    pos_rank_str_list = [ gen_label_name(item) for item in pos_rank_list]\n",
    "    counter = Counter(pos_rank_str_list)\n",
    "    result_dict = { k : v for k, v in counter.items()}\n",
    "\n",
    "    plt.figure(figsize=(6, 6))\n",
    "    plt.pie(result_dict.values(), labels=result_dict.keys(), autopct='%1.1f%%', startangle=140, labeldistance=1.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6c52044-b61b-41df-948b-c46dbdbad5a7",
   "metadata": {},
   "outputs": [],
   "source": [
    "result = rank_recalls([[\"为这个句子生成表示以用于检索相关文章：烘焙值可以用来做什么？\", \"指挥官可以使用自己的烘焙值在\\\"分享蛋糕\\\"页兑换奖品。使用烘焙值不会影响排行榜名次和累计值。\"],[\"为这个句子生成表示以用于检索相关文章：烘焙值可以用来做什么？\", \"甜美倾心-金甜甜圈的效果是全体单位生命增加，1级效果3%，每升1级增加3%。\"]], smr_client, endpoint_name)\n",
    "print(list(result))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4db934b1-c65b-42ec-a858-84a511e425a6",
   "metadata": {},
   "source": [
    "* check ranking ability without ranker （查看没有ranker模型时的排序效果）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 205,
   "id": "020a405a-ca97-47e8-810c-20b9e842596e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 500/500 [07:45<00:00,  1.07it/s]\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 600x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "pos_rank_list = []\n",
    "\n",
    "with open('./chatgpt_synthesis/test_merged_hardneg.jsonl', 'r') as input_f:\n",
    "    lines = input_f.readlines()\n",
    "    for line in tqdm(lines[:500]):\n",
    "        json_obj = json.loads(line)\n",
    "        query = json_obj['query']\n",
    "        pos = json_obj['pos']\n",
    "        negs = json_obj['neg']\n",
    "        neg_pairs = [ [query, neg] for neg in negs ]\n",
    "        pos_pairs = [[query, pos[0]]]\n",
    "        \n",
    "        pos_score = calc_emb_similarity(pos_pairs, smr_client, emb_endpoint_name='bge15-finetuned-2023-09-19-23-59-44-451-endpoint')\n",
    "        neg_scores = calc_emb_similarity(neg_pairs, smr_client, emb_endpoint_name='bge15-finetuned-2023-09-19-23-59-44-451-endpoint')\n",
    "        \n",
    "        neg_scores.sort(reverse=True)\n",
    "        \n",
    "        pos_rank = 0\n",
    "        for item in neg_scores:\n",
    "            if pos_score < item:\n",
    "                pos_rank += 1\n",
    "                \n",
    "        pos_rank_list.append(pos_rank)\n",
    "        \n",
    "plot_stat(pos_rank_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d14faf05-9db6-492d-8213-f07c296bc4a0",
   "metadata": {
    "tags": []
   },
   "source": [
    "* check ranking ability with ranker （查看有ranker模型时的排序效果）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 208,
   "id": "8f62b79a-5c9a-48d3-9914-f78b61c16de7",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 500/500 [00:26<00:00, 18.91it/s]\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 600x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from tqdm import tqdm\n",
    "\n",
    "pos_rank_list = []\n",
    "with open('./chatgpt_synthesis/test_merged_hardneg.jsonl', 'r') as input_f:\n",
    "    lines = input_f.readlines()\n",
    "    for line in tqdm(lines[:500]):\n",
    "        json_obj = json.loads(line)\n",
    "        query = json_obj['query']\n",
    "        pos = json_obj['pos']\n",
    "        negs = json_obj['neg']\n",
    "        neg_pairs = [ [query, neg] for neg in negs ]\n",
    "        pos_pair = [[query, pos[0]]]\n",
    "        \n",
    "        pospair_scores = call_ranker(pos_pair, smr_client, endpoint_name)\n",
    "        negpair_scores = call_ranker(neg_pairs, smr_client, endpoint_name)\n",
    "        \n",
    "        pos_scores = [ item[1] for item in pospair_scores ]\n",
    "        neg_scores = [ item[1] for item in negpair_scores ]\n",
    "        neg_scores.sort(reverse=True)\n",
    "        pos_score = pos_scores[0]\n",
    "        \n",
    "        pos_rank = 0\n",
    "        for item in neg_scores:\n",
    "            if pos_score < item:\n",
    "                pos_rank += 1\n",
    "                \n",
    "        pos_rank_list.append(pos_rank)\n",
    "\n",
    "plot_stat(pos_rank_list)\n"
   ]
  }
 ],
 "metadata": {
  "availableInstances": [
   {
    "_defaultOrder": 0,
    "_isFastLaunch": true,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 4,
    "name": "ml.t3.medium",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 1,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.t3.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 2,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.t3.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 3,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.t3.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 4,
    "_isFastLaunch": true,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.m5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 5,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.m5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 6,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.m5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 7,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.m5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 8,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.m5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 9,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.m5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 10,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.m5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 11,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.m5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 12,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.m5d.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 13,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.m5d.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 14,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.m5d.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 15,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.m5d.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 16,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.m5d.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 17,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.m5d.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 18,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.m5d.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 19,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.m5d.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 20,
    "_isFastLaunch": false,
    "category": "General purpose",
    "gpuNum": 0,
    "hideHardwareSpecs": true,
    "memoryGiB": 0,
    "name": "ml.geospatial.interactive",
    "supportedImageNames": [
     "sagemaker-geospatial-v1-0"
    ],
    "vcpuNum": 0
   },
   {
    "_defaultOrder": 21,
    "_isFastLaunch": true,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 4,
    "name": "ml.c5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 22,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 8,
    "name": "ml.c5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 23,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.c5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 24,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.c5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 25,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 72,
    "name": "ml.c5.9xlarge",
    "vcpuNum": 36
   },
   {
    "_defaultOrder": 26,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 96,
    "name": "ml.c5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 27,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 144,
    "name": "ml.c5.18xlarge",
    "vcpuNum": 72
   },
   {
    "_defaultOrder": 28,
    "_isFastLaunch": false,
    "category": "Compute optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.c5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 29,
    "_isFastLaunch": true,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.g4dn.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 30,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.g4dn.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 31,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.g4dn.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 32,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.g4dn.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 33,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.g4dn.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 34,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.g4dn.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 35,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 61,
    "name": "ml.p3.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 36,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 244,
    "name": "ml.p3.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 37,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 488,
    "name": "ml.p3.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 38,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.p3dn.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 39,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.r5.large",
    "vcpuNum": 2
   },
   {
    "_defaultOrder": 40,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.r5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 41,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.r5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 42,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.r5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 43,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.r5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 44,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.r5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 45,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 512,
    "name": "ml.r5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 46,
    "_isFastLaunch": false,
    "category": "Memory Optimized",
    "gpuNum": 0,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.r5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 47,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 16,
    "name": "ml.g5.xlarge",
    "vcpuNum": 4
   },
   {
    "_defaultOrder": 48,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 32,
    "name": "ml.g5.2xlarge",
    "vcpuNum": 8
   },
   {
    "_defaultOrder": 49,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 64,
    "name": "ml.g5.4xlarge",
    "vcpuNum": 16
   },
   {
    "_defaultOrder": 50,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 128,
    "name": "ml.g5.8xlarge",
    "vcpuNum": 32
   },
   {
    "_defaultOrder": 51,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 1,
    "hideHardwareSpecs": false,
    "memoryGiB": 256,
    "name": "ml.g5.16xlarge",
    "vcpuNum": 64
   },
   {
    "_defaultOrder": 52,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 192,
    "name": "ml.g5.12xlarge",
    "vcpuNum": 48
   },
   {
    "_defaultOrder": 53,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 4,
    "hideHardwareSpecs": false,
    "memoryGiB": 384,
    "name": "ml.g5.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 54,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 768,
    "name": "ml.g5.48xlarge",
    "vcpuNum": 192
   },
   {
    "_defaultOrder": 55,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 1152,
    "name": "ml.p4d.24xlarge",
    "vcpuNum": 96
   },
   {
    "_defaultOrder": 56,
    "_isFastLaunch": false,
    "category": "Accelerated computing",
    "gpuNum": 8,
    "hideHardwareSpecs": false,
    "memoryGiB": 1152,
    "name": "ml.p4de.24xlarge",
    "vcpuNum": 96
   }
  ],
  "instance_type": "ml.m5.large",
  "kernelspec": {
   "display_name": "Python 3 (PyTorch 2.0.0 Python 3.10 GPU Optimized)",
   "language": "python",
   "name": "python3__SAGEMAKER_INTERNAL__arn:aws:sagemaker:us-east-1:081325390199:image/pytorch-2.0.0-gpu-py310"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
